package com.parking.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.parking.common.core.model.PageInfo;
import com.parking.common.core.model.RedisKey;
import com.parking.common.core.model.StateData;
import com.parking.common.core.util.BeanUtilCommon;
import com.parking.common.web.util.RedisUtil;
import com.parking.order.client.dto.CertifiedInfoDto;
import com.parking.order.client.dto.UserInfoDto;
import com.parking.order.dao.OrderInfoDao;
import com.parking.order.model.OrderComment;
import com.parking.order.dao.OrderCommentDao;
import com.parking.order.model.OrderInfo;
import com.parking.order.model.dto.*;
import com.parking.order.model.exception.OrderException;
import com.parking.order.model.exception.OrderExceptionCode;
import com.parking.order.model.param.AddCommentParam;
import com.parking.order.model.param.FindCommentByOrderNumParam;
import com.parking.order.model.param.OrderCommentParam;
import com.parking.order.model.param.ReplyCommentParam;
import com.parking.order.service.IEntranceInfoService;
import com.parking.order.service.IOrderCommentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.parking.order.util.BasicInfoUtil;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 吴彦祖
 * @since 2023年11月28日
 */
@Service
public class OrderCommentServiceImpl extends ServiceImpl<OrderCommentDao, OrderComment> implements IOrderCommentService {
    /**
     * 订单评论数据层
     * */
    @Autowired
    private OrderCommentDao orderCommentDao;
    /**
     * 订单信息数据层
     * */
    @Autowired
    private OrderInfoDao orderInfoDao;
    /**
     * 其他服务调用工具类
     * */
    @Autowired
    private BasicInfoUtil basicInfoUtil;
    /**
     * 消息队列工具类
     * */
    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * Redis工具类
     * */
    @Autowired
    private RedisUtil redisUtil;
    /**
     * 进出口信息服务层
     * */
    @Autowired
    private IEntranceInfoService entranceInfoService;
    /**
     * 物业回复订单评论
     * 参数 Authorization 物业token
     *     commentId     订单评论Id
     *     replyInfo     回复内容
     * 返回 commentId 评论Id
     *     orderInfoNum 订单编号
     *     commentInfo 评论内容
     *     commentScore 评论分数
     *     commentTime 评论时间
     *     replyInfo   回复内容
     *     replyTime   回复时间
     *     userInfoId  用户信息Id
     *     userInfoName 用户姓名
     * */
    @Transactional
    @Override
    public ReplyCommentDto replyComment(ReplyCommentParam param) throws Exception {
        // 校验 回复Id与物业信息Id相符合
        OrderComment comment = orderCommentDao.selectById(param.getCommentId());
        CertifiedInfoDto certifiedInfo = basicInfoUtil.getCertifiedInfo(comment.getReplyId());
        if(!Objects.equals(certifiedInfo.getCertifiedAccountId(), param.getCertifiedId())) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NOT_BELONG_TO_THIS_CERTIFIED);

        // 回复评论
        LocalDateTime now = LocalDateTime.now();
        comment.setReplyInfo(param.getReplyInfo());
        comment.setReplyTime(now);
        orderCommentDao.updateById(comment);

        // 修改订单状态
        orderInfoDao.update(null,new UpdateWrapper<OrderInfo>().eq("order_info_num",comment.getOrderInfoNum()).set("order_update_time", now).set("is_comment",StateData.ORDER_IS_REPLY));

        // 添加订单日志
        rabbitTemplate.convertAndSend("orderLog",comment.getOrderInfoNum()+",物业回复订单,"+StateData.ORDER_LOG_PERSON_TYPE_CERTIFIED+","+certifiedInfo.getCertifiedInfoName());

        // 物业待回复差评统计
        if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_BAD)){
            int badCommentNum = Integer.parseInt(redisUtil.get(RedisKey.certifiedBadComment(comment.getReplyId())));
            redisUtil.set(RedisKey.certifiedBadComment(certifiedInfo.getCertifiedInfoId()), String.valueOf(badCommentNum-1));
        }

        // 返回Dto
        UserInfoDto user = basicInfoUtil.getUserInfo(comment.getUserInfoId());
        String commentScore = null;
        if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_GOOD)) commentScore = "Good";
        if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_BAD)) commentScore = "Bad";
        if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_OK)) commentScore = "OK";
        return new ReplyCommentDto(comment.getCommentId(),comment.getOrderInfoNum(),comment.getCommentInfo(),commentScore,comment.getCommentTime(),param.getReplyInfo(),now,comment.getUserInfoId(),user.getUserInfoName(),user.getUserInfoTel());
    }
    /**
     * 用户添加订单评论
     * 参数 Authorization 用户token
     *      orderInfoNum 订单编号
     *      commentInfo 评论内容
     *      commentScore 评论分数
     * 返回 commentId 评论Id
     *     orderInfoNum 订单编号
     *     commentInfo 评论内容
     *     commentScore 评论分数
     *     commentTime 评论时间
     *     certifiedInfoId 物业信息Id
     *     certifiedInfoName 物业名称
     *     certifiedInfoTel  物业电话
     *     certifiedInfoAddress 物业地址
     * */
    @Transactional
    @Override
    public AddCommentDto addComment(AddCommentParam param) throws Exception {
        // 校验 1.订单编号与用户Id符合 2.订单已完成且订单没有回复过
        OrderInfo order = orderInfoDao.selectOne(new QueryWrapper<OrderInfo>().eq("order_info_num", param.getOrderInfoNum()));
        if(order==null) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NOT_EXISTS);
        if(!Objects.equals(order.getOrderInfoState(), StateData.ORDER_STATE_END)) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_WRONG_ORDER_STATE);
        if(Objects.equals(order.getIsOvertime(), StateData.ORDER_IS_OVERTIME_NOT_FINISH)) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_OVERTIME_ORDER_NO_COMMENT);
        if(!Objects.equals(order.getIsComment(), StateData.ORDER_IS_NOT_COMMENT)) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_COMMENT_ALREADY);
        UserInfoDto user = basicInfoUtil.getUserInfo(order.getUserInfoId());
        if(!Objects.equals(user.getUserAccountId(), param.getUserId())) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NOT_BELONG_TO_THIS_USER);

        // 添加评论
        LocalDateTime now = LocalDateTime.now();
        OrderComment comment = new OrderComment(order.getOrderInfoId(),order.getUserInfoId(),param.getCommentInfo(), now,order.getCertifiedInfoId(),order.getOrderInfoNum());
        Integer commentScore = null;
        if(param.getCommentScore().equals("Good")) commentScore = StateData.COMMENT_SCORE_GOOD;
        if(param.getCommentScore().equals("Bad")) commentScore = StateData.COMMENT_SCORE_BAD;
        if(param.getCommentScore().equals("OK")) commentScore = StateData.COMMENT_SCORE_OK;
        comment.setCommentScore(commentScore);
        orderCommentDao.insert(comment);

        // 改变订单状态
        order.setIsComment(StateData.ORDER_IS_COMMENT_NO_REPLY);
        order.setOrderUpdateTime(now);
        order.setCommentScore(param.getCommentScore());
        orderInfoDao.updateById(order);

        // 添加订单日志
        rabbitTemplate.convertAndSend("orderLog",order.getOrderInfoNum()+",用户评论订单,"+StateData.ORDER_LOG_PERSON_TYPE_USER+","+user.getUserInfoName());

        // 物业待回复差评统计
        if(param.getCommentScore().equals("Bad")){
            if(redisUtil.exist(RedisKey.certifiedBadComment(order.getCertifiedInfoId()))){
                int badCommentNum = Integer.parseInt(redisUtil.get(RedisKey.certifiedBadComment(order.getCertifiedInfoId())));
                redisUtil.set(RedisKey.certifiedBadComment(order.getCertifiedInfoId()), String.valueOf(badCommentNum+1));
            }else{
                redisUtil.set(RedisKey.certifiedBadComment(order.getCertifiedInfoId()), "1");
            }
        }

        // 返回Dto
        CertifiedInfoDto certifiedInfo = basicInfoUtil.getCertifiedInfo(order.getCertifiedInfoId());
        return new AddCommentDto(comment.getCommentId(),order.getOrderInfoNum(),comment.getCommentInfo(),param.getCommentScore(),now,certifiedInfo.getCertifiedInfoId(),certifiedInfo.getCertifiedInfoName(),certifiedInfo.getCertifiedInfoTel(),certifiedInfo.getCertifiedInfoAddress());
    }
    /**
     * 平台查询评论
     * 参数 订单编号 orderInfoNum
     *     用户信息Id userInfoId
     *     开始时间 startTime
     *     结束时间 endTime
     *     订单评分 commentScore
     *     物业信息Id certifiedInfoId
     *     是否评论 isReply 0无回复 1有回复
     * 返回 评论Id commentId
     *     订单编号 orderInfoNum
     *     评论内容 commentInfo
     *     评论时间 commentTime
     *     评论分数 commentScore
     *     回复内容 replyInfo       // 没有回复不返回
     *     回复时间 replyTime       // 没有回复不返回
     *     物业信息Id certifiedInfoId
     *     物业名称 certifiedInfoName
     *     物业电话 certifiedInfoTel
     *     物业地址 certifiedInfoAddress
     *     用户信息Id userInfoId
     *     用户姓名   userInfoName
     *     用户电话   userInfoTel
     * */
    @Override
    public PageInfo findOrderCommentPlatform(OrderCommentParam param) throws Exception {
        Page<OrderComment> page = findOrderComment(param);
        if(Objects.equals(param.getIsReply(), StateData.COMMENT_IS_REPLY)) return fromPageToPageInfo(page, OrderCommentPlatformIsReplyDto.class);
        if(Objects.equals(param.getIsReply(), StateData.COMMENT_NO_REPLY)) return fromPageToPageInfo(page, OrderCommentPlatformNoReplyDto.class);
        return null;
    }

    /**
     * 根据订单编号查询订单评论
     * 参数 出租客Id rentersId
     *      用户Id  userId
     *      订单编号 orderInfoNum
     * 返回  评论内容 commentInfo
     *      评论时间 commentTime
     *      回复内容 replyInfo
     *      回复时间 replyTime
     *      订单评分 commentScore Good Bad OK
     * */
    @Override
    public CommentDto findCommentByOrderNum(FindCommentByOrderNumParam param) throws Exception {
        entranceInfoService.checkUserPlatformRentersForOrderInfoNum(param.getUserId(),null,param.getRentersId(),param.getOrderInfoNum());

        OrderComment comment = orderCommentDao.selectOne(new QueryWrapper<OrderComment>().eq("order_info_num", param.getOrderInfoNum()));
        if(comment==null) throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_ORDER_NO_COMMENT_INFO);
        CommentDto dto = BeanUtil.toBean(comment, CommentDto.class);

        String commentScore = null;
        if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_GOOD)) commentScore = "Good";
        if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_OK)) commentScore = "OK";
        if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_BAD)) commentScore = "Bad";
        dto.setCommentScore(commentScore);
        return dto;
    }

    /**
     * 物业查询评论
     * 参数 订单编号 orderInfoNum
     *     用户信息Id userInfoId
     *     开始时间 startTime
     *     结束时间 endTime
     *     订单评分 commentScore
     *     物业信息Id certifiedInfoId
     *     是否评论 isReply 0无回复 1有回复
     * 返回 评论Id commentId
     *     订单编号 orderInfoNum
     *     评论内容 commentInfo
     *     评论时间 commentTime
     *     评论分数 commentScore
     *     回复内容 replyInfo       // 没有回复不返回
     *     回复时间 replyTime       // 没有回复不返回
     *     用户信息Id userInfoId
     *     用户姓名   userInfoName
     *     用户电话   userInfoTel
     * */
    @Override
    public PageInfo findOrderCommentCertified(OrderCommentParam param) throws Exception {
        Page<OrderComment> page = findOrderComment(param);
        if(Objects.equals(param.getIsReply(), StateData.COMMENT_IS_REPLY)) return fromPageToPageInfo(page, OrderCommentCertifiedIsReplyDto.class);
        if(Objects.equals(param.getIsReply(), StateData.COMMENT_NO_REPLY)) return fromPageToPageInfo(page, OrderCommentCertifiedNoReplyDto.class);
        return null;
    }

    /**
     * 查询评论
     * 参数 订单编号 orderInfoNum
     *     用户信息Id userInfoId
     *     开始时间 startTime
     *     结束时间 endTime
     *     订单评分 commentScore
     *     物业信息Id certifiedInfoId
     *     是否评论 isReply 0无回复 1有回复
     *  返回 List<OrderComment>
     *      commentId   订单评论Id
     *      orderInfoId 订单Id
     *      userInfoId 用户信息Id
     *      commentInfo 评论内容
     *      commentTime 评论时间
     *      replyId     回复人Id = certifiedId
     *      replyInfo   回复内容
     *      replyTime   回复时间
     *      orderInfoNum 订单编号
     *      commentScore 订单评分
     * */
    private Page<OrderComment> findOrderComment(OrderCommentParam param){
        boolean isOrderInfoNum = param.getOrderInfoNum()!=null&&!param.getOrderInfoNum().equals("");
        boolean isUserInfoId = param.getUserInfoId()!=null;
        boolean isStartTime = param.getStartTime()!=null;
        boolean isEndTime = param.getEndTime()!=null;
        boolean isCommentScore = param.getCommentScore()!=null&&!param.getCommentScore().equals("");
        boolean isCertifiedInfoId = param.getCertifiedInfoId()!=null;
        boolean isReply = Objects.equals(param.getIsReply(), StateData.COMMENT_IS_REPLY);

        if(isStartTime&&isEndTime){
            if(!param.getStartTime().isBefore(param.getEndTime()))
                throw new OrderException(OrderExceptionCode.ORDER_EXCEPTION_CODE_START_NOT_BEFORE_END);
        }

        QueryWrapper<OrderComment> wrapper = new QueryWrapper<>();
        if(isOrderInfoNum) wrapper.eq("order_info_num",param.getOrderInfoNum());
        if(isUserInfoId) wrapper.eq("user_info_id",param.getUserInfoId());
        if(isCertifiedInfoId) wrapper.eq("reply_id",param.getCertifiedInfoId());
        if(isCommentScore){
            Integer commentScore = null;
            if(param.getCommentScore().equals("Good")) commentScore = StateData.COMMENT_SCORE_GOOD;
            if(param.getCommentScore().equals("Bad")) commentScore = StateData.COMMENT_SCORE_BAD;
            if(param.getCommentScore().equals("OK")) commentScore = StateData.COMMENT_SCORE_OK;
            wrapper.eq("comment_score",commentScore);
        }

        if(isReply) {
            wrapper.isNotNull("reply_info");
            if(isStartTime) wrapper.ge("reply_time",param.getStartTime());
            if(isEndTime) wrapper.le("comment_time",param.getEndTime());
            wrapper.orderByAsc("reply_time");
        }else{
            wrapper.isNull("reply_info");
            if(isStartTime) wrapper.ge("comment_time",param.getStartTime());
            if(isEndTime) wrapper.le("comment_time",param.getEndTime());
            wrapper.orderByAsc("comment_time");
        }

        Page<OrderComment> page = new Page<>(param.getPageNum(),param.getPageSize());
        orderCommentDao.selectPage(page,wrapper);
        return page;
    }

    /**
     * 返回PageInfo
     * 参数 Page<OrderComment>
     *     clazz dto类信息
     * 返回 PageInfo
     * 将 OrderComment 转为 OrderCommentPlatformIsReplyDto
     *                再转为 clazz
     * */
    private <T> PageInfo fromPageToPageInfo(Page<OrderComment> page, Class<T> clazz) throws Exception {
        List<OrderComment> records = page.getRecords();
        List<OrderCommentPlatformIsReplyDto> preDtos = new ArrayList<>();

        for (OrderComment comment : records) {
            OrderCommentPlatformIsReplyDto preDto = BeanUtil.toBean(comment,OrderCommentPlatformIsReplyDto.class);
            preDto.setCertifiedInfoId(comment.getReplyId());

            UserInfoDto user = basicInfoUtil.getUserInfo(preDto.getUserInfoId());
            preDto.setUserInfoName(user.getUserInfoName());
            preDto.setUserInfoTel(user.getUserInfoTel());

            CertifiedInfoDto certified = basicInfoUtil.getCertifiedInfo(preDto.getCertifiedInfoId());
            preDto.setCertifiedInfoName(certified.getCertifiedInfoName());
            preDto.setCertifiedInfoTel(certified.getCertifiedInfoTel());
            preDto.setCertifiedInfoAddress(certified.getCertifiedInfoAddress());

            String commentScore = null;
            if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_GOOD)) commentScore = "Good";
            if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_OK)) commentScore = "OK";
            if(Objects.equals(comment.getCommentScore(), StateData.COMMENT_SCORE_BAD)) commentScore = "Bad";
            preDto.setCommentScore(commentScore);

            preDtos.add(preDto);
        }

        List<T> dtos = BeanUtilCommon.BeanToList(preDtos,clazz);
        PageInfo pageInfo = BeanUtil.toBean(page, PageInfo.class);
        pageInfo.setPages(page.getPages());
        pageInfo.setTotal(page.getTotal());
        pageInfo.setRecords(dtos);
        return pageInfo;
    }
}
